package com.jrx.anytxn.transaction.service.impl;

import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.uitl.*;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.PrPenaltyRateTable;
import com.jrx.anytxn.param.entity.PrProductTable;
import com.jrx.anytxn.param.entity.TlFilePaymentLog;
import com.jrx.anytxn.param.service.product.IPrPenaltyRateTableService;
import com.jrx.anytxn.param.service.product.IProductTableService;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.param.utils.TargzUtil;
import com.jrx.anytxn.transaction.bean.PaphFileBean;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.entity.*;
import com.jrx.anytxn.transaction.mapper.ext.*;
import com.jrx.anytxn.transaction.service.IPaphFileService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: anytxn-cf-parent
 * @description:
 * @author: xiaoyu.jing
 * @date: 2021-03-12 09:44
 **/
@Service
public class PaphFileSeviceImpl implements IPaphFileService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private ExtAmLoanMainInfoMapper extLoanMainInfoMapper;
    @Resource
    private ExtAmRepaymentPlanInfoMapper extRepaymentPlanInfoMapper;
    @Resource
    private ExtAmInterestAccrualInfoMapper extAmInterestAccrualInfoMapper;
    @Resource
    private ExtAmAccountMainInfoMapper extAmAccountMainInfoMapper;
    @Autowired
    private IPrPenaltyRateTableService prPenaltyRateTableService;
    @Autowired
    private IProductTableService productTableService;
    @Autowired
    private IOrganizationTableService organizationTableService;
    @Resource
    private ExtTlPaymentAllocationLogMapper extTlPaymentAllocationLogMapper;
    @Resource
    private ExtAmRepaymentPlanInfoMapper extAmRepaymentPlanInfoMapper;
    @Resource
    private ExtTlThirdPartyPaymentMapper extTlThirdPartyPaymentMapper;
    @Resource
    private ExtAmLoanAccountInfoMapper extAmLoanAccountInfoMapper;

    /**
     * 前一日借款文件
     *
     * @param tlDisbursementLog
     * @return
     */
    @Override
    public PaphFileBean generateLoanMessage(TlDisbursementLog tlDisbursementLog) throws TxnBizException {
        String loanId = tlDisbursementLog.getLoanId();
        String customerId = tlDisbursementLog.getCustomerId();
        String tenantId = tlDisbursementLog.getTenantId();
        AmLoanMainInfo loanMainInfo = extLoanMainInfoMapper.selectByLoanIdAndCusId(loanId, customerId, tenantId);
        List<AmRepaymentPlanInfo> planInfoList = extRepaymentPlanInfoMapper.selectByLoanId(loanId, customerId, tenantId);

        BigDecimal yearRate = loanMainInfo.getInterestRate().multiply(new BigDecimal(100)).setScale(7, BigDecimal.ROUND_HALF_UP);
        PrPenaltyRateTable penaltyRateTable = prPenaltyRateTableService.findByPenaltyId(loanMainInfo.getPenaltyTableId(),
                loanMainInfo.getOrganizationId(), loanMainInfo.getTenantId());
        BigDecimal yearPenRate = prPenaltyRateTableService.getPenaltyDailyRate(yearRate, penaltyRateTable);

        StringBuilder sb = new StringBuilder();
        for (AmRepaymentPlanInfo plan : planInfoList) {
            sb.append("D").append(TransBizConstant.FILE_SEPARATOR);
            sb.append(loanId).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(this.transPlanStatus(plan.getPlanStatus())).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getBillingTenor()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(DateUtils.formatDate2(plan.getPaymentDueDate())).append(TransBizConstant.FILE_SEPARATOR);
            if (TransBizConstant.LOAN_PLAN_STATUS_7.equals(plan.getPlanStatus()) ||
                    TransBizConstant.LOAN_PLAN_STATUS_8.equals(plan.getPlanStatus())) {
                sb.append(DateUtils.formatDate2(plan.getTransactionDate()));
            }
            sb.append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearPenRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getPrincipalAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getInterestAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(BigDecimal.ZERO.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getPrincipalAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getInterestAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(BigDecimal.ZERO.toPlainString());
            sb.append(TransBizConstant.LINE_END);
        }

        PaphFileBean paphFileBean = new PaphFileBean();
        paphFileBean.setFileString(sb.toString());
        paphFileBean.setProductType(loanMainInfo.getLoanType());
        return paphFileBean;
    }

    /**
     * 宽限期外逾期文件
     *
     * @param amLoanAccountInfo
     * @return
     * @throws TxnBizException
     */
    @Override
    public PaphFileBean generateOverMessage(AmLoanAccountInfo amLoanAccountInfo) throws TxnBizException {
        String loanId = amLoanAccountInfo.getLoanId();
        String customerId = amLoanAccountInfo.getCustomerId();
        String tenantId = amLoanAccountInfo.getTenantId();
        AmLoanMainInfo loanMainInfo = extLoanMainInfoMapper.selectByLoanIdAndCusId(loanId, customerId, tenantId);
        List<AmRepaymentPlanInfo> planInfoList = extRepaymentPlanInfoMapper.selectByLoanId(loanId, customerId, tenantId);
        //罚息复利累计账户按期分组
        List<AmInterestAccrualInfo> accuAcctInfoList = extAmInterestAccrualInfoMapper.selectAllAccuAcct(loanId, customerId, tenantId,
                Arrays.asList(TransBizConstant.INTEREST_ACCRUAL_TYPE_10, TransBizConstant.INTEREST_ACCRUAL_TYPE_20), Collections.singletonList(TransBizConstant.ACCOUNT_STATUS_1));
        Map<Integer, BigDecimal> accuAcctMap = accuAcctInfoList.stream().collect(Collectors.groupingBy(AmInterestAccrualInfo::getBillingTenor
                , CollectorsUtils.summingBigDecimal(AmInterestAccrualInfo::getAccrualTotalAccruInterest)));

        //罚息复利交易账户按期分组
        List<AmAccountMainInfo> acctList = extAmAccountMainInfoMapper.selectAccounts(loanId,
                Arrays.asList(TransBizConstant.ACCOUNT_TYPE_11, TransBizConstant.ACCOUNT_TYPE_12),
                customerId, tenantId, Arrays.asList(TransBizConstant.ACCOUNT_STATUS_1, TransBizConstant.ACCOUNT_STATUS_2));
        Map<Integer, List<AmAccountMainInfo>> acctMap = acctList.stream().collect(Collectors.groupingBy(AmAccountMainInfo::getBillingTenor));

        PrProductTable prProductTable = productTableService.findProByProIdAndOrgId(amLoanAccountInfo.getProductId(),
                amLoanAccountInfo.getOrganizationId(), tenantId);
        Integer graceDays = prProductTable.getGraceDays();
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        Date businessDate = org.getNextProcessingDate();


        BigDecimal yearRate = loanMainInfo.getInterestRate().multiply(new BigDecimal(100)).setScale(7, BigDecimal.ROUND_HALF_UP);

        PrPenaltyRateTable penaltyRateTable = prPenaltyRateTableService.findByPenaltyId(loanMainInfo.getPenaltyTableId(),
                loanMainInfo.getOrganizationId(), loanMainInfo.getTenantId());
        BigDecimal yearPenRate = prPenaltyRateTableService.getPenaltyDailyRate(yearRate, penaltyRateTable);

        StringBuilder sb = new StringBuilder();
        for (AmRepaymentPlanInfo plan : planInfoList) {
            if (!TransBizConstant.LOAN_PLAN_STATUS_2.equals(plan.getPlanStatus())) {
                continue;
            }

            //过滤掉宽限期内的
            Date lastGraceDate = DateUtils.addDay(plan.getPaymentDueDate(), graceDays);
            if (businessDate.compareTo(lastGraceDate) <= 0) {
                continue;
            }

            int billingTenor = plan.getBillingTenor();


            sb.append("D").append(TransBizConstant.FILE_SEPARATOR);
            sb.append(loanId).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(this.transPlanStatus(plan.getPlanStatus())).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getBillingTenor()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(DateUtils.formatDate2(plan.getPaymentDueDate())).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearPenRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getPrincipalAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getInterestAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);

            //计算总罚息+复利
            List<AmAccountMainInfo> acctListPerTenor = acctMap.get(billingTenor);
            BigDecimal acctDueOInt = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(acctListPerTenor)) {
                acctDueOInt = acctListPerTenor.stream().map(AmAccountMainInfo::getPostingAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            BigDecimal accuDueOInt = Optional.ofNullable(accuAcctMap.get(billingTenor)).orElse(BigDecimal.ZERO);
            BigDecimal dueOInt = acctDueOInt.add(accuDueOInt).add(plan.getRepayPenaltyInterest()).add(plan.getRepayCompoundInterest());
            sb.append(dueOInt.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);

            sb.append(plan.getPrincipalAmount().subtract(plan.getRepayPrincipal()).toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getInterestAmount().subtract(plan.getRepayInterest()).toPlainString()).append(TransBizConstant.FILE_SEPARATOR);

            //计算尚欠罚息复利
            BigDecimal acctOweOInt = BigDecimal.ZERO;
            if (CollectionUtils.isNotEmpty(acctListPerTenor)) {
                acctOweOInt = acctListPerTenor.stream().map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            acctOweOInt = acctOweOInt.add(accuDueOInt);
            sb.append(acctOweOInt.toPlainString());
            sb.append(TransBizConstant.LINE_END);
        }

        PaphFileBean paphFileBean = new PaphFileBean();
        paphFileBean.setFileString(sb.toString());
        paphFileBean.setProductType(loanMainInfo.getLoanType());
        return paphFileBean;
    }

    /**
     * 前一日还款文件
     *
     * @param tlThirdPartyPayment
     * @return
     * @throws TxnBizException
     */
    @Override
    public PaphFileBean generatePayMessage(TlThirdPartyPayment tlThirdPartyPayment) throws TxnBizException {
        String loanId = tlThirdPartyPayment.getLoanId();
        String customerId = tlThirdPartyPayment.getCustomerId();
        String tenantId = tlThirdPartyPayment.getTenantId();
        AmLoanMainInfo loanMainInfo = extLoanMainInfoMapper.selectByLoanIdAndCusId(loanId, customerId, tenantId);
        List<AmRepaymentPlanInfo> planInfoList = extRepaymentPlanInfoMapper.selectByLoanId(loanId, customerId, tenantId);
        List<TlPaymentAllocationLog> logList = extTlPaymentAllocationLogMapper.selectBySeqNoAndTenantId(tlThirdPartyPayment.getSeqNo()
                , tlThirdPartyPayment.getTenantId());

        //罚息复利累计账户按期分组
        List<AmInterestAccrualInfo> accuAcctInfoList = extAmInterestAccrualInfoMapper.selectAllAccuAcct(loanId, customerId, tenantId,
                Arrays.asList(TransBizConstant.INTEREST_ACCRUAL_TYPE_10, TransBizConstant.INTEREST_ACCRUAL_TYPE_20), Collections.singletonList(TransBizConstant.ACCOUNT_STATUS_1));
        Map<Integer, BigDecimal> accuAcctMap = accuAcctInfoList.stream().collect(Collectors.groupingBy(AmInterestAccrualInfo::getBillingTenor
                , CollectorsUtils.summingBigDecimal(AmInterestAccrualInfo::getAccrualTotalAccruInterest)));

        PrProductTable prProductTable = productTableService.findProByProIdAndOrgId(tlThirdPartyPayment.getProductId(),
                tlThirdPartyPayment.getOrganizationId(), tenantId);
        Integer graceDays = prProductTable.getGraceDays();
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        Date businessDate = org.getNextProcessingDate();


        BigDecimal yearRate = loanMainInfo.getInterestRate().multiply(new BigDecimal(100)).setScale(7, BigDecimal.ROUND_HALF_UP);

        PrPenaltyRateTable penaltyRateTable = prPenaltyRateTableService.findByPenaltyId(loanMainInfo.getPenaltyTableId(),
                loanMainInfo.getOrganizationId(), loanMainInfo.getTenantId());
        BigDecimal yearPenRate = prPenaltyRateTableService.getPenaltyDailyRate(yearRate, penaltyRateTable);

        StringBuilder sb = new StringBuilder();
        //正常还款
        if (TransBizConstant.REPAYMENT_TYPE_PAY.equals(tlThirdPartyPayment.getPaymentType())) {
            AmRepaymentPlanInfo plan = planInfoList.stream().filter(planInfo -> planInfo.getBillingTenor().intValue() == logList.get(0).getBillingTenor())
                    .findFirst().get();
            sb.append("D").append(TransBizConstant.FILE_SEPARATOR);
            sb.append(loanId).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(this.transPlanStatus(plan.getPlanStatus())).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getBillingTenor()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(DateUtils.formatDate2(plan.getPaymentDueDate())).append(TransBizConstant.FILE_SEPARATOR);
            if (TransBizConstant.LOAN_PLAN_STATUS_7.equals(plan.getPlanStatus()) ||
                    TransBizConstant.LOAN_PLAN_STATUS_8.equals(plan.getPlanStatus())) {
                sb.append(DateUtils.formatDate2(plan.getTransactionDate()));
            }
            sb.append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearPenRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getPrincipalAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getInterestAmount()).append(TransBizConstant.FILE_SEPARATOR);


            BigDecimal dueOInt = BigDecimal.ZERO;
            BigDecimal oweCapital = BigDecimal.ZERO;
            BigDecimal oweInt = BigDecimal.ZERO;
            BigDecimal oweOInt = BigDecimal.ZERO;

            //计算总罚息+复利
            if (TransBizConstant.LOAN_PLAN_STATUS_2.equals(plan.getPlanStatus())) {
                dueOInt = Optional.ofNullable(accuAcctMap.get(plan.getBillingTenor())).orElse(BigDecimal.ZERO);
                oweCapital = plan.getPrincipalAmount().subtract(plan.getRepayPrincipal());
                oweInt = plan.getInterestAmount().subtract(plan.getRepayInterest());
                oweOInt = Optional.ofNullable(accuAcctMap.get(plan.getBillingTenor())).orElse(BigDecimal.ZERO);
            }

            sb.append(dueOInt.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(oweCapital.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(oweInt.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(oweOInt.toPlainString());
            sb.append(TransBizConstant.LINE_END);
        } else if (TransBizConstant.REPAYMENT_TYPE_OVERDUE.equals(tlThirdPartyPayment.getPaymentType())) {
            //逾期还款
            Map<Integer, List<TlPaymentAllocationLog>> logMap = logList.stream().collect(Collectors.groupingBy(TlPaymentAllocationLog::getBillingTenor));
            for(int tenor : logMap.keySet()) {
                AmRepaymentPlanInfo plan = planInfoList.stream().filter(planInfo -> planInfo.getBillingTenor() == tenor)
                        .findFirst().get();

                //过滤掉宽限期外并且逾期的
                Date lastGraceDate = DateUtils.addDay(plan.getPaymentDueDate(), graceDays);
                if (businessDate.compareTo(lastGraceDate) > 0
                        && TransBizConstant.LOAN_PLAN_STATUS_2.equals(plan.getPlanStatus())) {
                    continue;
                }

                sb.append("D").append(TransBizConstant.FILE_SEPARATOR);
                sb.append(loanId).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(this.transPlanStatus(plan.getPlanStatus())).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(plan.getBillingTenor()).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(DateUtils.formatDate2(plan.getPaymentDueDate())).append(TransBizConstant.FILE_SEPARATOR);
                if (TransBizConstant.LOAN_PLAN_STATUS_7.equals(plan.getPlanStatus()) ||
                        TransBizConstant.LOAN_PLAN_STATUS_8.equals(plan.getPlanStatus())) {
                    sb.append(DateUtils.formatDate2(plan.getTransactionDate()));
                }
                sb.append(TransBizConstant.FILE_SEPARATOR);
                sb.append(yearRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(yearPenRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(plan.getPrincipalAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(plan.getInterestAmount().toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
                sb.append((plan.getRepayPenaltyInterest().add(plan.getRepayCompoundInterest())).toPlainString()).append(TransBizConstant.FILE_SEPARATOR);


                BigDecimal oweCapital = BigDecimal.ZERO;
                BigDecimal oweInt = BigDecimal.ZERO;
                //计算总罚息+复利
                if (TransBizConstant.LOAN_PLAN_STATUS_2.equals(plan.getPlanStatus())) {
                    oweCapital = plan.getPrincipalAmount().subtract(plan.getRepayPrincipal());
                    oweInt = plan.getInterestAmount().subtract(plan.getRepayInterest());

                }
                sb.append(oweCapital.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(oweInt.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
                sb.append(BigDecimal.ZERO.toPlainString());
                sb.append(TransBizConstant.LINE_END);
            }
        } else if (TransBizConstant.REPAYMENT_TYPE_PRETERMINTION.equals(tlThirdPartyPayment.getPaymentType())) {
            //获取提前结清时的当期
            int minTenor = logList.stream().map(TlPaymentAllocationLog::getBillingTenor).min(Integer::compareTo).get();
            AmRepaymentPlanInfo plan = planInfoList.stream().filter(planInfo -> planInfo.getBillingTenor() == minTenor)
                    .findFirst().get();
            //算出还款本金和利息总金额
            Map<String, BigDecimal> repayMap = logList.stream().collect(Collectors.groupingBy(TlPaymentAllocationLog::getConnectAccountType
                    , CollectorsUtils.summingBigDecimal(TlPaymentAllocationLog::getPostingAmount)));


            sb.append("D").append(TransBizConstant.FILE_SEPARATOR);
            sb.append(loanId).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(this.transPlanStatus(plan.getPlanStatus())).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(plan.getBillingTenor()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(DateUtils.formatDate2(plan.getPaymentDueDate())).append(TransBizConstant.FILE_SEPARATOR);
            if (TransBizConstant.LOAN_PLAN_STATUS_7.equals(plan.getPlanStatus()) ||
                    TransBizConstant.LOAN_PLAN_STATUS_8.equals(plan.getPlanStatus())) {
                sb.append(DateUtils.formatDate2(plan.getTransactionDate()));
            }
            sb.append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(yearPenRate.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(repayMap.get(TransBizConstant.ACCOUNT_TYPE_06).toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            BigDecimal intr = Optional.ofNullable(repayMap.get(TransBizConstant.ACCOUNT_TYPE_04)).orElse(BigDecimal.ZERO);
            sb.append(intr.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(BigDecimal.ZERO.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(BigDecimal.ZERO.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(BigDecimal.ZERO.toPlainString()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(BigDecimal.ZERO.toPlainString());
            sb.append(TransBizConstant.LINE_END);
        }

        PaphFileBean paphFileBean = new PaphFileBean();
        paphFileBean.setFileString(sb.toString());
        paphFileBean.setProductType(loanMainInfo.getLoanType());
        return paphFileBean;
    }

    /**
     * 将数据写入文件
     *
     * @param messageList
     * @param filePath
     * @param fileName
     * @param fileType
     */
    @Override
    public void generateFile(List<String> messageList, String filePath, String fileName, String fileType, String productType) {
        String fileProductType = "";
        if (Constant.PRODECUT_TYPE_1.equals(productType)) {
            fileProductType = Constant.PRODECUT_TYPE_XF;
        } else {
            fileProductType = Constant.PRODECUT_TYPE_JY;
        }
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        String nextProcessingDate = DateUtils.format(org.getNextProcessingDate(), "yyyyMMdd");

        String allFileName = Constant.LS_BANK + fileProductType + "_" + nextProcessingDate + "_" + fileName + "_" + fileType + ".txt";

        String allFilePath = filePath + org.getTenantId() + File.separator + nextProcessingDate + File.separator + fileProductType + File.separator;

        Path planFile = Paths.get(allFilePath + allFileName);

        try (FileWriter bfw = new FileWriter(planFile.toFile(), true);
             BufferedWriter writer = new BufferedWriter(bfw, 10240)) {
            for (String message : messageList) {
                if (StringUtils.isBlank(message)) {
                    continue;
                }
                if (!message.endsWith(TransBizConstant.LINE_END)) {
                    message = message.concat(TransBizConstant.LINE_END);
                }
                writer.write(message);

            }
            writer.flush();
        } catch (IOException e) {
            logger.error("平安普惠同步文件" + allFileName + "异常，异常信息：", e);
            throw new RuntimeException(e);
        }
    }

    private String transPlanStatus(String planStatus) {
        if (TransBizConstant.LOAN_PLAN_STATUS_0.equals(planStatus)) {
            return TransBizConstant.FILE_LOAN_PLAN_STATUS_0;
        } else if (TransBizConstant.LOAN_PLAN_STATUS_1.equals(planStatus)) {
            return TransBizConstant.FILE_LOAN_PLAN_STATUS_0;
        } else if (TransBizConstant.LOAN_PLAN_STATUS_2.equals(planStatus)) {
            return TransBizConstant.FILE_LOAN_PLAN_STATUS_2;
        } else if (TransBizConstant.LOAN_PLAN_STATUS_7.equals(planStatus) ||
                TransBizConstant.LOAN_PLAN_STATUS_8.equals(planStatus)) {
            return TransBizConstant.FILE_LOAN_PLAN_STATUS_1;
        }
        return planStatus;
    }


    @Override
    public PaphFileBean generateBankDeductionMessage(TlFilePaymentLog item) throws TxnBizException {
        StringBuilder sb = new StringBuilder();
        sb.append(TransBizConstant.FILE_D).append(TransBizConstant.FILE_SEPARATOR);
        sb.append(item.getLoanId()).append(TransBizConstant.FILE_SEPARATOR);
        sb.append(DateUtils.format(item.getTradeDate(), DateUtils.DATE_PATTERN_ANOTHER)).append(TransBizConstant.FILE_SEPARATOR);
        sb.append(null != item.getBillingTenor() ?  item.getBillingTenor() : 0).append(TransBizConstant.FILE_SEPARATOR);
        sb.append( item.getTotalAmt()).append(TransBizConstant.FILE_SEPARATOR);
        sb.append( item.getPrinAmt()).append(TransBizConstant.FILE_SEPARATOR);
        sb.append( item.getIntrAmt()).append(TransBizConstant.FILE_SEPARATOR);
        sb.append( item.getPentAmt()).append(TransBizConstant.FILE_SEPARATOR);
        sb.append(item.getTradeFlag()).append(TransBizConstant.FILE_SEPARATOR);
        if(null !=item.getStatus()) {
            sb.append(item.getStatus()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(item.getReason()).append(TransBizConstant.FILE_SEPARATOR);
            sb.append(item.getTradeSeqNo()).append(TransBizConstant.LINE_END);
        }else{
            sb.append(TransBizConstant.LOAN_FAILED).append(TransBizConstant.FILE_SEPARATOR);
            sb.append("订单不存在").append(TransBizConstant.FILE_SEPARATOR);
            sb.append(item.getTradeSeqNo()).append(TransBizConstant.LINE_END);
        }
        PaphFileBean bean = new PaphFileBean();
        bean.setProductType(item.getProductType());
        bean.setFileString(sb.toString());
        return bean;
    }


    // 计算文件行数
    private String readLine(List<File> files) throws IOException {
        // 文件行数
        long line = 0;
        for (File f : files) {
            try (RandomAccessFile file = new RandomAccessFile(f, "r")) {
                while (StringUtils.isNotBlank(file.readLine())) {
                    line++;
                }
            }
        }
        return String.valueOf(line);
    }


    @Override
    public void mergeBankFile(String filePath, String fileCode, String productType) throws Exception {
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        String nextProcessDate = DateFormatUtils.format(org.getNextProcessingDate(), DateUtils.DATE_PATTERN_ANOTHER);
        // 合并文件
        filePath =
                filePath + org.getTenantId() + File.separator + nextProcessDate + File.separator + productType + File.separator;
        String txtFileName = Constant.LS_BANK + productType + nextProcessDate + fileCode + ".txt";
        File resultFile = new File(filePath + txtFileName);
        this.generateBankMergeFile(filePath, resultFile, nextProcessDate, fileCode, productType);
        // 生成md5文件
        String md5FileName = filePath + Constant.LS_BANK + productType + nextProcessDate + fileCode + ".md5";
        String md5String = Md5utils.getFileMD5String(resultFile);
        FileUtils.writeFile(md5FileName, Arrays.asList(md5String), "UTF-8");
    }

    private void generateBankMergeFile(String filePath, File resultFile, String nextProcessDate, String fileCode,
                                       String productType) throws IOException {
        File file = new File(filePath);
        File[] fileLists = file.listFiles();
        if (fileLists == null || fileLists.length == 0) {
            logger.error("》》》》平安普惠文件合并《《《《{}路径下不存在文件", filePath);
            throw new RuntimeException("文件合并，路径下不存在文件");
        }
        List<File> mergeList = new ArrayList<>();
        String fileName;
        for (File f : fileLists) {
            fileName = f.getName();
            boolean flag = !fileName.contains(Constant.LS_BANK) ||
                    !fileName.contains(productType) ||
                    !fileName.contains(nextProcessDate) ||
                    !fileName.contains(fileCode) ||
                    !".txt".equals(fileName.substring(fileName.lastIndexOf("."))) ||
                    fileName.endsWith(fileCode + ".txt");
            if (flag) {
                continue;
            }
            mergeList.add(f);
        }
        if (mergeList.size() <= 0) {
            logger.error("》》》》平安普惠文件合并《《《《未找到需要的文件,filePath：{},businessDate:{},fileCode:{}", filePath, nextProcessDate,
                    fileCode);
            throw new RuntimeException("文件合并，未找到需要的文件");
        }
        // 总笔数
        long count = 0;
        // 合并分库文件
        StringBuffer builder = new StringBuffer();
        for (int i = 0; i < mergeList.size(); i++) {
            String str;
            File file1 = mergeList.get(i);
            try (BufferedReader reader = new BufferedReader(new FileReader(file1))) {
                while ((str = reader.readLine()) != null) {
                    builder.append(str).append(TransBizConstant.LINE_END);
                }
            }
        }
        // 文件尾
        String lineCount = readLine(mergeList);
        String line = TransBizConstant.FILE_F + TransBizConstant.FILE_SEPARATOR + lineCount;
        // 文件头 eg: H|201710310231093440992|XXXX00720171031D001.txt|D001|1|20171031
        String fileHeader = TransBizConstant.FILE_H + TransBizConstant.FILE_SEPARATOR +
                SeqUtils.getSNByLength(32) + TransBizConstant.FILE_SEPARATOR +
                resultFile.getName() + TransBizConstant.FILE_SEPARATOR +
                fileCode + TransBizConstant.FILE_SEPARATOR +
                lineCount + TransBizConstant.FILE_SEPARATOR +
                nextProcessDate + TransBizConstant.LINE_END;
        FileWriter writer = new FileWriter(resultFile);
        writer.write(fileHeader);
        writer.write(builder.toString());
        writer.write(line);
        writer.flush();
    }

    /**
     * 提前结清证明处理
     *
     * @param basePath     保存回传影像的路径
     * @param fromBasePath 回传影像的获取路径
     * @author liuyang
     * @date 2021-03-27
     */
    @Override
    public void disposePreterminationFile(String basePath, String fromBasePath) throws TxnException {

        // 查询机构信息
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        String todayStr = DateUtils.format(org.getToday(), DateUtils.DATE_PATTERN_ANOTHER);

        // 创建存放目录
        StringBuilder savePathSb = new StringBuilder();
        savePathSb.append(basePath).append(File.separator).append(org.getTenantId()).append(File.separator).append(todayStr);
        String savePath = savePathSb.toString();
        FileUtils.createDirectories(savePath);

        // 获取提前结清还款流水
        List<Long> preterminationPaymentIds = extTlThirdPartyPaymentMapper.selectIdByTypeAndStatus(org.getToday(),
                TransBizConstant.REPAYMENT_TYPE_PRETERMINTION, TransBizConstant.PAYMENT_LOG_SUM_STATUS_S, TransBizConstant.PAPH_CHANNEL);
        if (CollectionUtils.isEmpty(preterminationPaymentIds)) {
            logger.info("日期[{}]没有提前结清数据。", org.getToday());
            return;
        }

        for (Long id : preterminationPaymentIds) {

            TlThirdPartyPayment tlThirdPartyPayment = extTlThirdPartyPaymentMapper.selectByPrimaryKey(id);

            AmLoanMainInfo amLoanMainInfo = extLoanMainInfoMapper.selectByLoanIdAndTenantId(tlThirdPartyPayment.getLoanId(), org.getTenantId());

            // 文件名
            StringBuilder preCertFileNameSb = new StringBuilder();
            preCertFileNameSb.append(TransBizConstant.LS_BANK).append("-").append(amLoanMainInfo.getContractNumber()).append("-").append(
                    TransBizConstant.PA_ADVSTLE).append("-").append("01").append(".pdf");
            String preCertFileName = preCertFileNameSb.toString();

            // 源文件路径
            StringBuilder fromPathSb = new StringBuilder();
            fromPathSb.append(fromBasePath).append(File.separator).append(org.getTenantId()).append(File.separator)
                    .append(DateUtils.format(tlThirdPartyPayment.getCreateTime(), DateUtils.DATE_PATTERN_ANOTHER));
            String fromPath = fromPathSb.toString();

            // 源文件全路径
            StringBuilder fromFilePathSb = new StringBuilder();
            fromFilePathSb.append(fromPath).append(File.separator).append(preCertFileName);
            String fromFilePath = fromFilePathSb.toString();

            if (FileUtils.isExists(fromFilePath)) {
                // 移动提前结清证明文件，文件拷贝，如果文件已经存在，则该方法会直接替换。
                FileUtils.copyFile(fromPath, savePath, preCertFileName);
                logger.info("提前结清证明[{}]移动完成。", fromFilePath);
            } else {
                logger.error("提前结清[{}]没有对应的提前结清证明：{}", id, fromFilePath);
            }
        }
    }

    /**
     * 借款合同文件处理
     *
     * @param basePath     保存回传影像的路径
     * @param fromBasePath 回传影像的获取路径
     * @author liuyang
     * @date 2021-03-27
     */
    @Override
    public void disposeContractFile(String basePath, String fromBasePath) throws TxnException {

        // 查询机构信息
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        String todayStr = DateUtils.format(org.getToday(), DateUtils.DATE_PATTERN_ANOTHER);

        // 创建存放目录
        StringBuilder savePathSb = new StringBuilder();
        savePathSb.append(basePath).append(File.separator).append(org.getTenantId()).append(File.separator).append(todayStr);
        String savePath = savePathSb.toString();
        FileUtils.createDirectories(savePath);

        // 查询昨日的订单
        List<String> loanIds = extLoanMainInfoMapper.selectLoanIdByPostingDateForBatch(org.getToday());
        if (CollectionUtils.isEmpty(loanIds)) {
            logger.info("日期[{}]没有借款合同。", org.getToday());
            return;
        }

        // 源路径
        StringBuilder fromPathSb = new StringBuilder();
        fromPathSb.append(fromBasePath).append(File.separator).append(org.getTenantId());
        String fromPath = fromPathSb.toString();

        for (String loanId : loanIds) {

            AmLoanMainInfo amLoanMainInfo = extLoanMainInfoMapper.selectByLoanIdAndTenantId(loanId, org.getTenantId());

            // 借款合同文件名
            StringBuilder contractFileNameSb = new StringBuilder();
            contractFileNameSb.append(TransBizConstant.LS_BANK).append("-").append(amLoanMainInfo.getContractNumber()).append("-").append(
                    TransBizConstant.PA_LOANINFO).append("-").append("01").append(".pdf");
            String contractFileName = contractFileNameSb.toString();

            // 目标文件全路径
            StringBuilder toFilePathSb = new StringBuilder();
            toFilePathSb.append(savePath).append(File.separator).append(contractFileName);
            String toFilePath = toFilePathSb.toString();

            // 源文件全路径
            StringBuilder fromFilePathSb = new StringBuilder();
            fromFilePathSb.append(fromPath).append(File.separator).append(amLoanMainInfo.getContractNumber()).append(File.separator).append("loaninfo.pdf");
            String fromFilePath = fromFilePathSb.toString();

            if (FileUtils.isExists(fromFilePath)) {
                // 移动借款合同文件，如果文件已经存在，则该方法会直接替换。
                FileUtils.copyFile(fromFilePath, toFilePath);
                logger.info("借款合同[{}]移动完成。", fromFilePath);
            } else {
                logger.error("借款[{}]没有对应的借款合同：{}", loanId, fromFilePath);
            }
        }
    }

    /**
     * 提前结清证明，借款合同打包
     *
     * @param basePath 保存回传影像的路径
     * @author liuyang
     * @date 2021-03-27
     */
    @Override
    public void compressPreContFile(String basePath) throws TxnException {

        // 查询机构信息
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        String todayStr = DateUtils.format(org.getToday(), DateUtils.DATE_PATTERN_ANOTHER);
        String businessDateStr = DateUtils.format(org.getNextProcessingDate(), DateUtils.DATE_PATTERN_ANOTHER);

        // 存放路径
        StringBuilder savePathSb = new StringBuilder();
        savePathSb.append(basePath).append(File.separator).append(org.getTenantId()).append(File.separator).append(todayStr);
        String savePath = savePathSb.toString();

        // 获取文件列表
        List<File> files = FileUtils.findFiles(savePath);

        // 开始压缩各个文件
        LinkedList<String> fileDatas = new LinkedList<>(); // ok文件数据
        int count = 0; // tar包个数
        if (CollectionUtils.isNotEmpty(files)) {
            for (File file : files) {
                String fileName = file.getName();
                if (fileName.endsWith(".pdf")) {
                    if (fileName.lastIndexOf(TransBizConstant.PA_ADVSTLE) > -1) {
                        // 提前结清证明压缩包文件名
                        StringBuilder tarAdvStleFileNameSb = new StringBuilder();
                        tarAdvStleFileNameSb.append(fileName.substring(0, fileName.lastIndexOf("-"))).append(".tar");
                        String tarAdvStleFileName = tarAdvStleFileNameSb.toString();

                        // 提前结清证明压缩包全路径
                        StringBuilder tarAdvStleFilePathSb = new StringBuilder();
                        tarAdvStleFilePathSb.append(savePath).append(File.separator).append(tarAdvStleFileName);
                        String tarAdvStleFilePath = tarAdvStleFilePathSb.toString();

                        // 如果压缩包已经存在，则删除，支持重跑。
                        if (FileUtils.isExists(tarAdvStleFilePath)) {
                            FileUtils.deleteFile(tarAdvStleFilePath);
                        }

                        // 压缩提前结清证明
                        File tarAdvStleFile = new File(tarAdvStleFilePath);
                        TargzUtil.pack(Arrays.asList(file), tarAdvStleFile);
                        logger.info("平安普惠影像回传的提前结清证明[{}]压缩完成。", tarAdvStleFilePath);
                        fileDatas.add(new StringBuilder().append(TransBizConstant.FILE_D).append(TransBizConstant.FILE_SEPARATOR).append(tarAdvStleFileName).toString());
                        count++;
                        continue;
                    }
                    if (fileName.lastIndexOf(TransBizConstant.PA_LOANINFO) > -1) {
                        // 借款合同压缩包文件名
                        StringBuilder tarLoaninfoFileNameSb = new StringBuilder();
                        tarLoaninfoFileNameSb.append(fileName.substring(0, fileName.lastIndexOf("-"))).append(".tar");
                        String tarLoaninfoFileName = tarLoaninfoFileNameSb.toString();

                        // 借款合同压缩包全路径
                        StringBuilder tarLoaninfoFilePathSb = new StringBuilder();
                        tarLoaninfoFilePathSb.append(savePath).append(File.separator).append(tarLoaninfoFileName);
                        String tarLoaninfoFilePath = tarLoaninfoFilePathSb.toString();

                        // 如果压缩包已经存在，则删除，支持重跑。
                        if (FileUtils.isExists(tarLoaninfoFilePath)) {
                            FileUtils.deleteFile(tarLoaninfoFilePath);
                        }

                        // 压缩借款合同
                        File tarLoaninfoFile = new File(tarLoaninfoFilePath);
                        TargzUtil.pack(Arrays.asList(file), tarLoaninfoFile);
                        fileDatas.add(new StringBuilder().append(TransBizConstant.FILE_D).append(TransBizConstant.FILE_SEPARATOR).append(tarLoaninfoFileName).toString());
                        count++;
                        logger.info("平安普惠影像回传的借款合同[{}]压缩完成。", tarLoaninfoFilePath);
                        continue;
                    }
                }
            }
        }

        // 生成OK文件
        StringBuilder okFileNameSb = new StringBuilder();
        okFileNameSb.append(TransBizConstant.LS_BANK).append(TransBizConstant.PA_CUSTINFOBACKTOPA).append("-").append(businessDateStr).append("OK").append(".txt");
        String okFileName = okFileNameSb.toString();
        StringBuilder okFilePathSb = new StringBuilder();
        okFilePathSb.append(savePath).append(File.separator).append(okFileName);
        String okFilePath = okFilePathSb.toString();

        // 如果ok文件已经存在，则删除，支持重跑
        if (FileUtils.isExists(okFilePath)) {
            FileUtils.deleteFile(okFilePath);
        }

        // ok文件头
        String fileHeader = this.getHeader(okFileName, TransBizConstant.PA_CUSTINFOBACKTOPA, count, org.getNextProcessingDate());
        fileDatas.addFirst(fileHeader);
        // ok文件尾
        StringBuilder fileTailSb = new StringBuilder();
        fileTailSb.append(TransBizConstant.FILE_F).append(TransBizConstant.FILE_SEPARATOR).append(count);
        fileDatas.addLast(fileTailSb.toString());
        // 写入ok文件
        FileUtils.writeFile(okFilePath, fileDatas, "UTF-8");

        // 生成md5文件
        StringBuilder md5FileNameSb = new StringBuilder();
        md5FileNameSb.append(TransBizConstant.LS_BANK).append(TransBizConstant.PA_CUSTINFOBACKTOPA).append("-").append(businessDateStr).append("OK").append(".md5");
        String md5FileName = md5FileNameSb.toString();
        StringBuilder md5FilePathSb = new StringBuilder();
        md5FilePathSb.append(savePath).append(File.separator).append(md5FileName);
        String md5FilePath = md5FilePathSb.toString();
        try {
            // 如果md5文件已经存在，则删除，支持重跑
            if (FileUtils.isExists(md5FilePath)) {
                FileUtils.deleteFile(md5FilePath);
            }
            String md5Data = Md5utils.getFileMD5String(new File(okFilePath));
            FileUtils.writeFile(md5FilePath, Arrays.asList(md5Data), "UTF-8");
        } catch (Exception e) {
            logger.error("文件[{}]生成md5文件失败：{}", okFilePath, e);
            throw new TxnException("文件[" + okFilePath + "]生成md5文件失败：" + e.getMessage());
        }
    }

    /**
     * 生成文件头
     *
     * @param fileName
     * @param fileCode
     * @param count
     * @param date
     * @return
     */
    private String getHeader(String fileName, String fileCode, Integer count, Date date) {

        String dateStr = DateUtils.format(date, DateUtils.DATE_PATTERN_ANOTHER);

        StringBuilder fileHeaderSb = new StringBuilder();
        fileHeaderSb.append(TransBizConstant.FILE_H).append(TransBizConstant.FILE_SEPARATOR).append(SeqUtils.getSNByLength(32))
                .append(TransBizConstant.FILE_SEPARATOR).append(fileName).append(TransBizConstant.FILE_SEPARATOR).append(fileCode)
                .append(TransBizConstant.FILE_SEPARATOR).append(count).append(TransBizConstant.FILE_SEPARATOR).append(dateStr);
        String fileHeader = fileHeaderSb.toString();

        return fileHeader;
    }
}


